﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using UnityEngine.Events;

namespace Elvex
{
    public class TCPSession : NetSession
    {
        public TCPSession(Socket socket):base(socket)
        {
            Read();
        }

        public override bool Deliver(byte[] buffer)
        {
            bool iswrite = m_writeQueue.Count <= 0;
            m_writeQueue.Enqueue(buffer);
            if (iswrite)
            {
                Wirte();
            }
            return true;
        }

        #region Write
        private Queue<byte[]> m_writeQueue = new Queue<byte[]>();

        private int m_writeBufferSize = 1024;

        public void SetWriteBufferSize(int size)
        {
            m_writeBufferSize = size;
        }

        /// <summary>
        /// 单次读取缓存大小
        /// </summary>
        public int WriteBufferSize { get{ return m_writeBufferSize; } }

        /// <summary>
        /// 读取偏移值
        /// </summary>
        private int m_writeOffset = 0;

        /// <summary>
        ///  发送信息
        /// </summary>
        private void Wirte()
        {
            if (m_writeQueue.Count <= 0)
            {
                return;
            }
            m_writeOffset = 0;
            try
            {
                m_socket.BeginSend(BitConverter.GetBytes(m_writeQueue.Peek().Length), 0, sizeof(uint), SocketFlags.None, (res) => {
                    if (!m_socket.Connected )
                    {
                        return;
                    }
                    WriteBody();
                }, m_socket);
            }
            catch (Exception e)
            {
                UnityEngine.Debug.Log("SocketException:" + e.ToString());
                //OnError?.Invoke(e);
            }
        }

        private void WriteBody()
        {
            try
            {
                int writelength = m_writeQueue.Peek().Length - m_writeOffset;
                if (writelength >= m_writeBufferSize) writelength = m_writeBufferSize;
                m_socket.BeginSend(m_writeQueue.Peek(), m_writeOffset, writelength, SocketFlags.None, (res) => {
                    if (!m_socket.Connected)
                    {
                        return;
                    }

                    try
                    {
                        m_writeOffset += m_socket.EndSend(res);
                        if (m_writeOffset >= m_writeQueue.Peek().Length)
                        {
                            m_writeQueue.Dequeue();
                            Wirte();
                        }
                        else
                        {
                            WriteBody();
                        }
                    }
                    catch (Exception e)
                    {
                        UnityEngine.Debug.LogErrorFormat("Exception msg:{0}", e.Message);
                        //OnError?.Invoke(e);
                    }
                }, m_socket);
            }
            catch (SocketException e)
            {
                UnityEngine.Debug.Log("SocketException:" + e.ToString());
                //gLog.Log(Log.LogLevel.Debug, "\nResponseCallback Exception raised!");
                //gLog.Log(Log.LogLevel.Debug, "\nMessage:{0}", e.Message);
                //gLog.Log(Log.LogLevel.Debug, "\nStatus:{0}", e.Status);
                //OnError?.Invoke(e);
            }
        }

        #endregion Write

        #region Read
        private byte[] m_readBuffer = null;

        /// <summary>
        /// 读取偏移值
        /// </summary>
        private int m_readOffset = 0;

        private int m_readBufferSize = 1024;

        public void SetReadBufferSize(int size)
        {
            m_readBufferSize = size;
        }

        /// <summary>
        /// 单次读取缓存大小
        /// </summary>
        public int ReadBufferSize { get { return m_readBufferSize; } }

        /// <summary>
        /// 接受信息
        /// </summary>
        /// <returns></returns>
        private void Read()
        {
            m_readOffset = 0;
            try
            {
                byte[] bodylength = new byte[sizeof(UInt32)];
                m_socket.BeginReceive(bodylength, 0, bodylength.Length, SocketFlags.None, (res) => {
                    if (!m_socket.Connected)
                    {
                        return;
                    }
                    m_readBuffer = new byte[BitConverter.ToUInt32(bodylength, 0)];
                    ReadBody();
                }, m_socket);
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogErrorFormat("Exception msg:{0}", e.Message);
            }
        }

        private void ReadBody()
        {
            try
            {
                int readlength = m_readBuffer.Length - m_readOffset;
                if (readlength >= m_readBufferSize) { readlength = m_readBufferSize; }
                m_socket.BeginReceive(m_readBuffer, m_readOffset, readlength, SocketFlags.None, (res) => {
                    if (!m_socket.Connected)
                    {
                        return;
                    }

                    try
                    {
                        m_readOffset += m_socket.EndReceive(res);
                        if (m_readOffset >= m_readBuffer.Length)
                        {
                            // 发送到数据缓存中
                            NetManager.Instance.AddMessage(this, m_readBuffer);
                            Read();
                        }
                        else
                        {
                            ReadBody();
                        }
                    }
                    catch (Exception e)
                    {
                        UnityEngine.Debug.LogErrorFormat("Exception msg:{0}", e.Message);
                        //OnError?.Invoke(e);
                    }
                }, m_socket);
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogErrorFormat("Exception msg:{0}", e.Message);
                //OnError?.Invoke(e);
            }
        }

        #endregion Read
    }
}
